package com.xiaogang.ggfw.utils.sign;

import cn.hutool.core.codec.Base64;
import cn.hutool.extra.spring.SpringUtil;
import com.xiaogang.ggfw.model.sys.mid.SignCacheBean;
import com.xiaogang.ggfw.model.sys.mid.SignMapBean;
import com.xiaogang.ggfw.model.sys.po.SignModelBean;
import com.xiaogang.ggfw.utils.common.APIRs;
import com.xiaogang.ggfw.utils.common.SimpleTools;
import org.springframework.util.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.UUID;

/**
 * @ProjectName : caldav
 * @作者 : 侯小刚
 * @描述 : 签名工具类
 * @创建日期 : 2023/4/10 11:50
 */
public class SignUtils {

    public static final String SIGN_CACHE_KEY = "signs";

    private static final String SIGN_METHOD = "HmacSHA256";

    public static boolean checkSign(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String authorization = getAuthorization(httpServletRequest);
        if(StringUtils.hasLength(authorization)) {
            SignModelBean signModelBean = analysisSign(authorization);
            if(null == signModelBean) {
                SimpleTools.responseJsonString(httpServletResponse, APIRs.signError());
                return false;
            }

            // 校验时间是否过期
            if(System.currentTimeMillis() - Long.parseLong(signModelBean.getTime()) > 1000 * 60 * 5) {
                SimpleTools.responseJsonString(httpServletResponse, APIRs.signTimeout());
                return false;
            }

            // 根据key获取密钥
            for (SignCacheBean signCacheBean : SignMapBean.signCacheBeans) {
                if(signCacheBean.getAppKey().equals(signModelBean.getAppKey())) {
                    try {
                        String secret = signCacheBean.getAppSecret();
                        String signature = structSignOrigin(signModelBean,secret,httpServletRequest);
                        if(signature.equals(signModelBean.getSignature())) {
                            return true;
                        }
                    }catch (Exception e) {
                        SimpleTools.responseJsonString(httpServletResponse, APIRs.signError());
                        return false;
                    }
                    SimpleTools.responseJsonString(httpServletResponse, APIRs.signError());
                    return false;
                }
            }
            SimpleTools.responseJsonString(httpServletResponse, APIRs.signKeyError());
            return false;
        }
        SimpleTools.responseJsonString(httpServletResponse, APIRs.signEmpty());
        return false;
    }

    /**
     * 构建签名原文
     * @param signModelBean
     * @param secret
     * @return
     */
    private static String structSignOrigin(SignModelBean signModelBean, String secret, HttpServletRequest httpServletRequest) throws Exception {
        String uuid = "uuid: " + signModelBean.getUuid();
        String time = "time: " + signModelBean.getTime();
        // 大写
        String method = httpServletRequest.getMethod() + " ";
        String uri = httpServletRequest.getRequestURI();
        String signOrigin = uuid + "\n" + time + "\n" + method + uri + "\n";
        String sign = hmacSHA256Encode(secret, signOrigin);
        return sign;
    }

    /**
     * 获取请求头
     * @param req
     * @return
     */
    private static String getAuthorization(HttpServletRequest req) {
        String auth = req.getHeader("Authorization");
        if (null == auth) {
            auth = req.getHeader("authorization");
        }
        return auth;
    }

    /**
     * Base64编码.
     */
    public static String base64Encode(byte[] input) {
        return Base64.encode(input);
    }

    /**
     * Base64解码.
     */
    public static byte[] base64Decode(String input) {
        return Base64.decode(input);
    }

    /**
     * 将加密后的字节数组转换成字符串
     * @param b 字节数组
     * @return 字符串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b!=null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }

    /**
     * sha256_HMAC加密
     * @param secret  秘钥
     * @param message 消息
     * @return 加密后字符串
     */
    public static String hmacSHA256Encode(String secret, String message) throws Exception {
        Mac hmacSha256 = Mac.getInstance(SIGN_METHOD);
        SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), SIGN_METHOD);
        hmacSha256.init(secret_key);
        byte[] bytes = hmacSha256.doFinal(message.getBytes());
        return byteArrayToHexString(bytes);
    }

    /**
     * 生成签名
     * @param method
     * @param uri
     * @param appKey
     * @param secret
     * @return
     */
    public static String getSignatureOrigin(String method,String uri,String appKey,String secret) throws Exception{
        String uuid = UUID.randomUUID().toString();
        String time = String.valueOf(System.currentTimeMillis());
        String signOrigin = "uuid: " + uuid + "\ntime: " + time + "\n" + method + " " + uri + "\n";
        String sign = hmacSHA256Encode(secret, signOrigin);
        SignModelBean build = SignModelBean.builder()
                .signature(sign)
                .time(time)
                .uuid(uuid)
                .appKey(appKey)
                .build();
        return base64Encode(build.toString().getBytes());
    }

    /**
     * 解析签名
     * @param sign
     * @return
     */
    public static SignModelBean analysisSign(String sign) {
        // base64解码
        String decode = new String(Base64.decode(sign));
        String[] split = decode.split(",");
        if(split.length == 4) {
            try{
                String appKey = split[0].split("=")[1].replace("\"","");
                String uuid = split[1].split("=")[1].replace("\"","");
                String time = split[2].split("=")[1].replace("\"","");
                String signature = split[3].split("=")[1].replace("\"","");
                if(signature.endsWith(")") || signature.endsWith("}")) {
                    signature = signature.substring(0,signature.length()-1);
                }
                return SignModelBean.builder()
                        .appKey(appKey)
                        .uuid(uuid)
                        .time(time)
                        .signature(signature)
                        .build();
            }catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    public static void main(String[] args) throws Exception {
        String appKey = "69221d55-1d80-4776-b348-bc9e5fdab211";
        String appSecret = "b70c2950-72ba-41dd-8314-a21077eddfc0";
        String get = getSignatureOrigin("POST", "/api/v1/service/dealOfd/ofdToImg", appKey, appSecret);
        System.out.println(get);
        System.out.println(new String(Base64.decode(get)));
        SignModelBean signModelBean = analysisSign(get);
        System.out.println(signModelBean);
    }
}
